package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"net"
)

func read(conn net.Conn) (string, error) {

	// 读取消息长度
	length, err := readLength(conn)

	//fmt.Println("length =", length)

	if err != nil {
		return "", err
	}

	// 读取消息体数据
	buf := make([]byte, length)

	// 读取数据
	_, err = conn.Read(buf[:length])

	if err == io.EOF {
		return "", err
	}

	if err != nil {
		fmt.Printf("Read data error=%v\n", err)
		return "", err
	}

	// 返回
	return string(buf[:length]), nil
}

func readLength(conn net.Conn) (int, error) {

	// 缓冲区
	buf := make([]byte, 4)

	var length = 0

	for {

		// 读取数据
		l, err := conn.Read(buf[length:4])

		if err == io.EOF {
			return -1, err
		}

		if err != nil {
			fmt.Printf("ReadUint32 error=%v\n", err)
			return -1, err
		}

		if l+length >= 4 {
			break
		}

		length = length + l
	}

	//fmt.Println(buf)

	return int(binary.BigEndian.Uint32(buf[0:4])), nil
}

func process(conn net.Conn) {

	defer func() {
		fmt.Printf("Close connection from %v\n", conn.RemoteAddr().String())
		conn.Close()
	}()

	// 循环读取数据
	for {

		line, err := read(conn)

		if err == io.EOF {
			break
		}

		if err != nil {
			fmt.Printf("Read data error=%v\n", err)
			break
		}

		fmt.Printf("%v\n", line)
	}
}

func simpleProcess(conn net.Conn) {

	defer func() {
		fmt.Printf("Close connection from %v\n", conn.RemoteAddr().String())
		conn.Close()
	}()

	// 循环读取数据
	for {

		// 缓冲区
		buf := make([]byte, 2048)

		// 读取数据
		n, err := conn.Read(buf)

		if err == io.EOF {
			break
		}

		if err != nil {
			fmt.Printf("Read data error=%v\n", err)
			break
		}

		fmt.Printf("%v\n", string(buf[:n]))
	}
}

func main() {

	address := "0.0.0.0:9999"

	// 启动监听
	listen, err := net.Listen("tcp", address)

	if err != nil {
		fmt.Printf("Net listen error=%v\n", err)
		return
	}

	// 关闭监听
	defer listen.Close()

	fmt.Printf("Start server, listening at %v\n", address)

	for {

		// 阻塞接收连接
		conn, err := listen.Accept()

		if err != nil {
			fmt.Printf("Accept connection error=%v\n", err)
			continue
		}

		fmt.Printf("Accept connection from %v\n", conn.RemoteAddr().String())

		// 启动协程处理请求
		go process(conn)
		//go simpleProcess(conn)
	}
}
